#include "proxy/conn/tcpaccpetserver.h"


namespace proxy{

  TcpAccpetServer::TcpAccpetServer(
    ios_deque& io_services,
    boost::asio::io_service& accpet_service,
    std::string addr, uint16 port)
    :io_services_(io_services),
    accpet_service_(accpet_service),
    bind_addr_(boost::asio::ip::address().from_string(addr), port),
    stop_(true){
    DLOG(INFO) << bind_addr_.address().to_string() << ":" << port;
  }

  TcpAccpetServer::~TcpAccpetServer(){
    DLOG(WARNING) << "Delete TcpAccpetServer::~TcpAccpetServer";
  }

  bool TcpAccpetServer::Start(){
    if (!stop_){
      DLOG(ERROR) << "The TcpServer is not stop, you should not Start agian";
      return false;
    }
    try{
      acceptor_.reset(new boost::asio::ip::tcp::acceptor(accpet_service_, bind_addr_.protocol()));
      acceptor_->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
      acceptor_->bind(bind_addr_);
      acceptor_->listen();
    }
    catch (std::exception& e){
      std::cout << e.what() << std::endl;
      DLOG(ERROR) << e.what();
      return false;
    }
    stop_ = false;
    accpet_service_.post(
      boost::bind(&TcpAccpetServer::HandleStartAcceptor, shared_from_this()));
    return true;
  }

  void TcpAccpetServer::Stop(){
    if (stop_){
      return;
    }
    else{
      // Fast stop this server
      stop_ = true;
      accpet_service_.post(
        boost::bind(&TcpAccpetServer::HandleStopTcpServer, shared_from_this()));
    }
  }

  void TcpAccpetServer::HandleStartAcceptor(){
    if (stop_){
      DLOG(WARNING) << "The TcpServer was stoped";
      return;
    }
    if (!acceptor_){
      DLOG(ERROR) << "The Acceptor is null";
      return;
    }
    if (io_services_.size() > 0){
      socket_ptr connect(new boost::asio::ip::tcp::socket(get_best_io_server()));
      acceptor_->async_accept(*connect.get(),
        boost::bind(&TcpAccpetServer::HandleAcceptor, shared_from_this(),
        connect, boost::asio::placeholders::error));
    }
  }

  void TcpAccpetServer::HandleAcceptor(
    socket_ptr connect, const boost::system::error_code& err){

    if (stop_){
      DLOG(WARNING) << "The TcpServer was stoped";
      return;
    }

    if (err){
      stop_ = true;
      DLOG(ERROR) << err.message();
      SignalAcceptError(shared_from_this(), err);
      return;
    }
    SignalNewConnect(shared_from_this(), connect);
    HandleStartAcceptor();
  }

  void TcpAccpetServer::HandleStopTcpServer(){
    if (acceptor_){
      acceptor_->close();
    }
  }
  boost::asio::io_service& TcpAccpetServer::get_best_io_server(){
    io_services_.push_back(io_services_.front());
    io_services_.pop_front();
    return *io_services_.front();
  }
} // namespace proxy